/*! \file logparser.cpp
    \brief This file contains implementation of class ARSARSLogFileAdapter.
    \version 1.0
*/

#include <QMessageBox>
#include <QDomDocument>
#include <QMetaProperty>
#include <QDebug>

#include "logfileadapter.h"

QHash<int, QRegExp> g_LogStrMap;

///////// Class 'ARSLogFileAdapter' implementation ///////////////////////////////////////////////////

LogFileAdapter::LogFileAdapter(QObject * parent)
    : QObject(parent)
{
}

QString LogFileAdapter::name() const
{
    return "logfileadapter";
}

QString LogFileAdapter::description() const
{
    return tr("This plugin provides ARS log files hadling.");
}

DynamicModel * LogFileAdapter::createModel(QIODevice * source)
{
    ARSExecItem * currentItem;
    ARSExecItem * tmpItem;
    QString line;
    int lineNumber = 1;
    int serverSideRemoveLen = -1;
    ARSExecWorkflowObject::ObjectType arsObjectType;
    bool fltrGuideReturn = false;
    ObjectsManagment objectManagmentType;

    ARSExecModelRootItem * rootItem = new ARSExecModelRootItem();
    DynamicModel * model = new DynamicModel(rootItem);
    currentItem = rootItem;
    bool skipLine = false;

    while(!source->atEnd())
    {
        skipLine = false;
        line = source->readLine();

        if(line.trimmed().isEmpty())
            continue;

        arsObjectType = objectType(line);

        objectManagmentType = Unknown;

        /*! \todo parse server side properties */
        switch(lineType(line))
        {
        case LineFilter:
            if(serverSideRemoveLen == -1)
                serverSideRemoveLen = serverPropertiesLen(line);

            line.remove(0, serverSideRemoveLen);
            break;
        case LineActiveLink:
            line.remove(0, g_LogStrMap[ACTL].pattern().length());
            break;
        case LineSql:
            if(serverSideRemoveLen == -1)
                serverSideRemoveLen = serverPropertiesLen(line);

            line.remove(0, serverSideRemoveLen);
            objectManagmentType = ObjectLineSql;
            break;
        case LineApi:
            if(serverSideRemoveLen == -1)
                serverSideRemoveLen = serverPropertiesLen(line);

            line.remove(0, serverSideRemoveLen);
            objectManagmentType = ObjectLineApi;
            break;
        case LineClat:
            objectManagmentType = ObjectLineClat;
            break;
        }

        line = line.trimmed();
        if(objectManagmentType == Unknown)
            objectManagmentType = itemMark(line);

        switch(objectManagmentType)
        {
        case WorkflowRoot:
            if(currentItem->type() != ARSExecItem::ItemTypeRoot)
            {
                tmpItem = new ARSExecRootItem(currentItem);
                currentItem = tmpItem;
            }

            break;
        case WorkflowBlockBegin:
            while(!(currentItem->type() & (ARSExecItem::ItemTypeAction | ARSExecItem::ItemTypeRoot)))
                    currentItem = currentItem->parent();

            if(arsObjectType == ARSExecWorkflowObject::ActiveLink)
                tmpItem = new ARSExecActlBlock(currentItem);
            else
                tmpItem = new ARSExecFltrBlock(currentItem);

            currentItem = tmpItem;

            break;
        case WorkflowBlockEnd:
            while(!(currentItem->type() & (ARSExecItem::ItemTypeWorkflowBlock | ARSExecItem::ItemTypeRoot)))
                    currentItem = currentItem->parent();

            if(currentItem->type() != ARSExecItem::ItemTypeRoot)
                currentItem = currentItem->parent();

            break;
        case WorkflowGuideBegin:
            tmpItem = new ARSExecGuide(currentItem);
            currentItem = tmpItem;

            break;
        case WorkflowGuideEnd:
            if(arsObjectType == ARSExecWorkflowObject::Filter)
                fltrGuideReturn = true;

            while(!(currentItem->type() & (ARSExecItem::ItemTypeGuide | ARSExecItem::ItemTypeRoot)))
                    currentItem = currentItem->parent();

            if(currentItem->type() != ARSExecItem::ItemTypeRoot)
                currentItem = currentItem->parent();

            break;
        case WorkflowObjectBegin:
            while(!(currentItem->type() & (ARSExecItem::ItemTypeWorkflowBlock |
                    ARSExecItem::ItemTypeGuide |ARSExecItem::ItemTypeRoot)))
            {
                currentItem = currentItem->parent();
            }

            if(arsObjectType == ARSExecWorkflowObject::ActiveLink)
                tmpItem = new ARSExecActl(currentItem);
            else
                tmpItem = new ARSExecFltr(currentItem);

            currentItem = tmpItem;

            break;
        case WorkflowActionBegin:
            while(!(currentItem->type() & (ARSExecItem::ItemTypeWorkflowObject | ARSExecItem::ItemTypeRoot)))
                    currentItem = currentItem->parent();

            if(currentItem->type() == ARSExecItem::ItemTypeWorkflowObject)
            {
                ARSExecWorkflowObject * workflowObject = static_cast<ARSExecWorkflowObject *>(currentItem);
                if(workflowObject->type() == ARSExecWorkflowObject::ActiveLink)
                {
                    ARSExecActl * execActiveLink = static_cast<ARSExecActl *>(workflowObject);
                    ARSDummyActiveLink * activeLink = execActiveLink->activeLink();
                    if(activeLink)
                    {
                       activeLink->setStatus(ARSDummyObject::Primary);
                    }
                    else
                        qDebug(qPrintable(line + " parent active link is NULL"));
                }
                else
                {
                    ARSExecFltr * execFltr = static_cast<ARSExecFltr *>(workflowObject);
                    ARSDummyFilter * filter = execFltr->filter();
                    if(filter)
                    {
                        filter->setStatus(ARSDummyObject::Primary);
                    }
                    else
                        qDebug(qPrintable(line + " parent filter is NULL"));
                }
            }

            tmpItem = createAction(actionType(line), currentItem);
            if(tmpItem)
                currentItem = tmpItem;
            else
                qDebug(qPrintable("LogFileAdapter::createModel: action is not found.\n" + line));

            break;
        case WorkflowFieldAssign:
            while(!(currentItem->type() & (ARSExecItem::ItemTypeAction | ARSExecItem::ItemTypeRoot)))
                    currentItem = currentItem->parent();

            tmpItem = new ARSExecFieldAssign(currentItem);
            currentItem = tmpItem;

            break;
        case ObjectLineSql:
            while(!(currentItem->type() & (ARSExecItem::ItemTypeAction | ARSExecItem::ItemTypeRoot |
                                           ARSExecItem::ItemTypeWorkflowObject | ARSExecItem::ItemTypeWorkflowBlock)))
                    currentItem = currentItem->parent();

            tmpItem = new ARSExecSQLLine(currentItem);
            currentItem = tmpItem;

            break;
        case ObjectLineApi:
            while(!(currentItem->type() & (ARSExecItem::ItemTypeAction | ARSExecItem::ItemTypeRoot |
                                           ARSExecItem::ItemTypeWorkflowObject | ARSExecItem::ItemTypeWorkflowBlock)))
                    currentItem = currentItem->parent();

            tmpItem = new ARSExecAPILine(currentItem);
            currentItem = tmpItem;

            break;
        case ObjectLineClat:
            skipLine = true;
            break;
        }

        line = parseDateTime(currentItem, line);
        ARSExecWorkflowBlock * workflowBlock;
        ARSExecWorkflowObject * workflowObject;
        if(fltrGuideReturn)
            fltrGuideReturn = false;
        else
        {
            if(!skipLine)
            {
                switch(currentItem->type())
                {
                case ARSExecItem::ItemTypeRoot:
                        parseModelRoot(currentItem, line);
                    break;
                case ARSExecItem::ItemTypeWorkflowBlock:
                    workflowBlock = static_cast<ARSExecWorkflowBlock *>(currentItem);
                    if(workflowBlock->objectsType() == ARSExecWorkflowObject::ActiveLink)
                        parseALWorkflowBlockLine(model->index(), static_cast<ARSExecActlBlock *>(currentItem), line);
                    else
                        parseFltrWorkflowBlockLine(model->index(), static_cast<ARSExecFltrBlock *>(currentItem), line);
                    break;
                case ARSExecItem::ItemTypeGuide:
                    parseWorkflowGuideLine(model->index(), static_cast<ARSExecGuide *>(currentItem), line, arsObjectType);
                    break;
                case ARSExecItem::ItemTypeWorkflowObject:
                    workflowObject = static_cast<ARSExecWorkflowObject *>(currentItem);
                    if(workflowObject->objectType() == ARSExecWorkflowObject::ActiveLink)
                        parseALWorkflowObjectLine(model->index(), static_cast<ARSExecActl *>(currentItem), line);
                    else
                        parseFltrWorkflowObjectLine(model->index(), static_cast<ARSExecFltr *>(currentItem), line);
                    break;
                case ARSExecItem::ItemTypeAction:
                    parseActionLine(model->index(), static_cast<ARSExecAction *>(currentItem), line, arsObjectType);
                    break;
                case ARSExecItem::ItemTypeFieldAssign:
                    parseFieldAssign(model->index(), static_cast<ARSExecFieldAssign *>(currentItem), line);
                    break;
                case ARSExecItem::ItemTypeSQLLine:
                    parseSQLLine(static_cast<ARSExecSQLLine *>(currentItem), line);
                    break;
                case ARSExecItem::ItemTypeAPILine:
                    parseAPILine(static_cast<ARSExecAPILine *>(currentItem), line);
                    break;
                }

                if(currentItem->type() == ARSExecItem::ItemTypeAction &&
                   arsObjectType == ARSExecWorkflowObject::Filter)
                {
                    ARSExecAction * action = static_cast<ARSExecAction *>(currentItem);

                    if(action->actionType() == ARSExecAction::CallGuide)
                    {
                        ARSExecActionCallGuide * callGuideAction = static_cast<ARSExecActionCallGuide *>(currentItem);
                        ARSExecGuide * guide = new ARSExecGuide(currentItem);
                        guide->setObjectsType(ARSExecWorkflowObject::Filter);
                        guide->setGuide(callGuideAction->guide());
                        currentItem = guide;
                    }
                }

//                if(currentItem->type() == ARSExecItem::ItemTypeAction &&
//                   arsObjectType == ARSExecWorkflowObject::ActiveLink)
//                {
//                    ARSExecAction * action = static_cast<ARSExecAction *>(currentItem);

//                    if(action->actionType() == ARSExecAction::CloseWindow)
//                    {
//                        bool openWindowFound = false;
//                        ARSExecItem * item = currentItem;
//                        while(item->type() != ARSExecItem::ItemTypeRoot && !openWindowFound)
//                        {
//                            if(item->type() == ARSExecItem::ItemTypeAction)
//                            {
//                                action = static_cast<ARSExecAction *>(item);
//                                if(action->actionType() == ARSExecAction::OpenWindow)
//                                {
//                                    currentItem = item->parent();
//                                    openWindowFound = true;
//                                }
//                            }

//                            item = item->previousItem();
//                        }
//                    }
//                }
            }

        }

        lineNumber++;
    }

    return model;
}

bool LogFileAdapter::loadSettings()
{
    QString locale = "German";
    QFile file(":/settings/parserkeys");
    QDomDocument keysDocument;

    if(!file.open(QIODevice::ReadOnly))
        return false;

    if(!keysDocument.setContent(&file))
    {
        file.close();
        return false;
    }

    file.close();

    QDomNode rootNode = keysDocument.firstChildElement("ARSLogsReader");
    QDomElement keyElement = rootNode.firstChildElement("Keys");

    while((!keyElement.isNull()) && (keyElement.attribute("locale") != locale))
          keyElement = keyElement.nextSiblingElement();

    if(keyElement.isNull())
        return false;

    keyElement = keyElement.firstChildElement("Key");

    while(!keyElement.isNull())
    {
        g_LogStrMap.insert(keyElement.attribute("id").toInt(0, 10),
                           QRegExp(keyElement.attribute("Pattern"),
                                   (Qt::CaseSensitivity)keyElement.attribute("CaseSensivity").toInt(0, 10),
                                   (QRegExp::PatternSyntax)keyElement.attribute("PatternSyntax").toInt(0, 10)));

        keyElement = keyElement.nextSiblingElement();
    }

    return true;
}

QString LogFileAdapter::parseDateTime( ARSExecItem * item, const QString & line )
{
    int index;
    QString currentLine  = line;
    QString timeLine  = line;
    if(currentLine.indexOf(g_LogStrMap[TIMESTAMP]) != 0)
        return line;

    index = currentLine.indexOf(g_LogStrMap[TIMESTAMPEND]);
    timeLine = currentLine.left(index);
    currentLine.remove(0, index + g_LogStrMap[TIMESTAMPEND].pattern().length());
    index = timeLine.indexOf(g_LogStrMap[TIMESTAMPSTART]);
    timeLine.remove(0, index);
    timeLine = timeLine.trimmed();
    timeLine = timeLine.left(QString("hh:mm:ss.zzz").length());
    QTime time = QTime::fromString(timeLine, "hh:mm:ss.zzz");
    if(!time.isValid())
        return line;

    item->setTime(time);
    return currentLine;
}

bool LogFileAdapter::parseModelRoot( ARSExecItem * item, const QString & line )
{
    QString propertyLine = line;
    ARSExecRootItem * rootItem = static_cast<ARSExecRootItem *>(item);

    int index = propertyLine.indexOf(g_LogStrMap[LOG_CREATE_DATE]);
    if(index != -1)
    {
        propertyLine.remove(0, index);
        propertyLine.remove(propertyLine.length() - 3, 3);
        propertyLine = propertyLine.trimmed();
        int month = createDateMonth(line);
        propertyLine = QString::number(month) + " " + propertyLine;
        QDateTime dateTime = QDateTime::fromString(propertyLine, "M dd yyyy hh:mm:ss");
        rootItem->setCreateDateTime(dateTime);
    }

    propertyLine = line;
    if(propertyLine.contains(g_LogStrMap[USER_VERSION]))
    {
        propertyLine.remove(0, g_LogStrMap[USER_VERSION].pattern().length());
        propertyLine = propertyLine.trimmed();
        propertyLine.remove(0, g_LogStrMap[USER_VERSION_VERSION].pattern().length());
        rootItem->setUserVersion(propertyLine.trimmed());
    }

    return true;
}

bool LogFileAdapter::parseALWorkflowBlockLine( ObjectsIndex * objectsIndex, ARSExecActlBlock * item, const QString & line )
{
    int index;
    QString property;

    index = line.indexOf(g_LogStrMap[PACKAGE_EVENT]);
    if(index != -1)
    {
        property = line;
        property.remove(0, index + g_LogStrMap[PACKAGE_EVENT].pattern().length());
        item->setEvent(eventType(property.trimmed()));

        return true;
    }

    index = line.indexOf(g_LogStrMap[ACTL_SCREEN_TYPE]);
    if(index != -1)
    {
        property = line;
        property.remove(0, index + g_LogStrMap[ACTL_SCREEN_TYPE].pattern().length());
        item->setScreenType(screenType(property.trimmed()));

        return true;
    }

    index = line.indexOf(g_LogStrMap[LINKED_TO_FIELD]);
    if(index != -1)
    {
        property = line;
        property.remove(0, index + g_LogStrMap[LINKED_TO_FIELD].pattern().length());

        QString fieldName = property.trimmed();
        index = fieldName.lastIndexOf(g_LogStrMap[FIELD_ID]);
        int fieldID = 0;
        if(index != -1)
        {
            QString fieldIdStr = fieldName.mid(index + 1, fieldName.length() - (index + 2));
            fieldID = fieldIdStr.toInt();
        }

        item->setLinkedField(objectsIndex->addField(const_cast<ARSDummyForm *>(item->form()), fieldName, fieldID, item));

        return true;
    }

    index = line.indexOf(g_LogStrMap[ACTL_PACKAGE_SCHEMA]);
    if(index != -1)
    {
        property = line;
        property.remove(0, index + g_LogStrMap[ACTL_PACKAGE_SCHEMA].pattern().length());
        property = property.trimmed();
        item->setForm(objectsIndex->addForm(property, item));

        return true;
    }

    return true;
}

bool LogFileAdapter::parseFltrWorkflowBlockLine( ObjectsIndex * objectsIndex, ARSExecFltrBlock * item, const QString & line )
{
    int index;
    QString property;
    QString tmpLine = line.trimmed();

    index = tmpLine.indexOf(g_LogStrMap[PHASE]);
    if(index != -1)
    {
        tmpLine.remove(0, index);
        index = tmpLine.indexOf(QRegExp("\\d+"));
        tmpLine.remove(0, index);
        property = tmpLine.left(1);
        item->setPhase(static_cast<ARSExecFltrBlock::Phase>(property.toInt(0, 10)));
        tmpLine.remove(0, 3);
    }

    index = tmpLine.indexOf(g_LogStrMap[PACKAGE_EVENT]);
    if(index != -1)
    {
        tmpLine.remove(0, index + g_LogStrMap[PACKAGE_EVENT].pattern().length());
        property = tmpLine;

        index = property.indexOf(g_LogStrMap[FLTR_PACKAGE_SCHEMA]);
        if(index != -1)
        {
            property = property.left(index);
            tmpLine.remove(0, index);
        }

        item->setEvent(eventType(property.trimmed()));
    }

    index = tmpLine.indexOf(g_LogStrMap[FLTR_PACKAGE_SCHEMA]);
    if(index != -1)
    {
        property = tmpLine;
        property.remove(0, g_LogStrMap[FLTR_PACKAGE_SCHEMA].pattern().length());
        QString schemaWithReqID = property;

        index = property.indexOf(g_LogStrMap[FLTR_PACKAGE_SEPARATOR]);
        if(index != -1)
            property = property.left(index);

        property = property.trimmed();
        item->setForm(objectsIndex->addForm(property, item));

        schemaWithReqID.remove(0, index + g_LogStrMap[FLTR_PACKAGE_SEPARATOR].pattern().length());
        schemaWithReqID = schemaWithReqID.trimmed();
        if(schemaWithReqID != g_LogStrMap[REQUEST_ID_NULL].pattern())
            item->setRequestID(schemaWithReqID.trimmed());
    }

    return true;
}

bool LogFileAdapter::parseWorkflowGuideLine( ObjectsIndex * objectsIndex, ARSExecGuide * item,
                                           const QString & line,
                                           ARSExecWorkflowObject::ObjectType arsObjectType )
{
    int index;
    QString property;

    item->setObjectsType(arsObjectType);

    index = line.indexOf(g_LogStrMap[ACTL_GUIDE_START]);

    if(index != -1)
    {
        property = line;
        property.remove(0, index + g_LogStrMap[ACTL_GUIDE_START].pattern().length());

        property = property.trimmed();

        item->setGuide(objectsIndex->addGuide(property, arsObjectType, item));
    }

    return true;
}

/*
bool LogFileAdapter::parseWorkflowObject( DebugWorkflowObject * item, const QString & line )
{
    int type;

    if(item->objectType == DebugWorkflowObject::PropertyNone)
    {
        type = objectType(line);
        if(type == DebugWorkflowObject::PropertyUnknown)
        {
            outStream << "Error: " << "Unknown object type at \"" << line << "\"" << endl;
            return false;
        }

        item->objectType = type;
    }

    if(item->objectType == DebugWorkflowObject::ActiveLink)
        parseALWorkflowObjectLine(item, line);
    else
        parseFltrWorkflowObjectLine(item, line);

    return true;
} */

bool LogFileAdapter::parseALWorkflowObjectLine( ObjectsIndex * objectsIndex, ARSExecActl * item, const QString & line )
{
    int index;
    QString property;

    if(!item->activeLink())
    {
        index = line.indexOf(g_LogStrMap[ACTL_EXECUTION]);
        if(index != -1)
        {
            property = line;
            property.remove(0, index + g_LogStrMap[ACTL_EXECUTION].pattern().length());

            index = property.indexOf(g_LogStrMap[EXEC_ORDER]);
            if(index != -1)
            {
                ARSDummyActiveLink * activeLink = objectsIndex->addActiveLink(property.left(index).trimmed(), item);
                item->setActiveLink(activeLink);
                property.remove(0, index);
                property = property.trimmed();
                property.remove(0, 1);
                property = property.left(property.length() - 1);
                item->setExecutionOrder(property.toInt());
            }
        }
    }

    if(line.contains(g_LogStrMap[ACTL_Q_PASSED]))
        item->setExecState(ARSExecWorkflowObject::StateQPassed);
    else
        if(line.contains(g_LogStrMap[ACTL_Q_FAILED]))
            item->setExecState(ARSExecWorkflowObject::StateQFailed);

    return true;
}

bool LogFileAdapter::parseFltrWorkflowObjectLine( ObjectsIndex * objectsIndex, ARSExecFltr * item, const QString & line )
{
    int index;
    QString property;

    if(!item->filter())
    {
        index = line.indexOf(g_LogStrMap[FLTR_EXECUTION]);
        if(index != -1)
        {
            property = line;

            property.remove(0, index + g_LogStrMap[FLTR_EXECUTION].pattern().length());
            property = property.trimmed();

            if(index != -1)
            {
                QRegExp nameRegExp = g_LogStrMap[FLTR_NAME];
                nameRegExp.indexIn(property);
                int nameEndIndex = nameRegExp.matchedLength();
                QString filterName = property.left(nameEndIndex);
                filterName = filterName.trimmed();
                filterName.remove(0, 1);
                filterName.remove(filterName.length() - 1, 1);
                ARSDummyFilter * filter = objectsIndex->addFilter(filterName, item);
                item->setFilter(filter);

                bool convertOk;
                int execOrder;
                property.remove(0, nameEndIndex);
                property = property.trimmed();
                if(!property.isEmpty())
                {
                    property.remove(0, 1);
                    property = property.left(property.length() - 1);
                    execOrder = property.toInt(&convertOk);
                    if(convertOk)
                        item->setExecutionOrder(property.toInt());
                }
            }
            else
            {
                property = property.trimmed();
                property.remove(0, 1);
                property.remove(property.length() - 1, 1);
                item->setFilter(objectsIndex->addFilter(property, item));
            }
        }
        else
        {
            index = line.indexOf(g_LogStrMap[FLTR_SKIPPED]);
            if(index != -1)
            {
                property = line;

                property.remove(0, index + g_LogStrMap[FLTR_SKIPPED].pattern().length());
                property = property.trimmed();

                int execOrderIndex = property.lastIndexOf("(");
                if(execOrderIndex != -1)
                {
                    QString filterName = property.left(execOrderIndex);
                    filterName = filterName.trimmed();
                    ARSDummyFilter * filter = objectsIndex->addFilter(filterName, item);
                    item->setFilter(filter);

                    QString execOrder = property;
                    execOrder.remove(0, execOrderIndex + 1);
                    execOrder.remove(execOrder.length() - 1, 1);
                    item->setExecutionOrder(execOrder.toInt());
                }
            }
        }
    }

    if(line.contains(g_LogStrMap[FLTR_Q_PASSED]))
        item->setExecState(ARSExecWorkflowObject::StateQPassed);
    else
        if(line.contains(g_LogStrMap[FLTR_Q_FAILED]))
            item->setExecState(ARSExecWorkflowObject::StateQFailed);
        else
            if(line.contains(g_LogStrMap[FLTR_DISABLED]))
                item->setExecState(ARSExecWorkflowObject::StateDisabled);
            else
                if(line.contains(g_LogStrMap[FLTR_SKIPPED]))
                    item->setExecState(ARSExecWorkflowObject::StateSkipped);

    return true;
}

bool LogFileAdapter::parseActionLine( ObjectsIndex * objectsIndex, ARSExecAction * item, const QString & line,
                                    ARSExecWorkflowObject::ObjectType arsObjectType )
{
    QRegExp phaseRegExp = g_LogStrMap[FLTR_ACTION_ADJOURNED];
    int phaseIndex = phaseRegExp.indexIn(line);
    if(phaseIndex != -1)
    {
        QString phaseString = line.mid(phaseIndex, phaseRegExp.matchedLength() - phaseIndex);
        phaseString = phaseString.right(2);
        phaseString = phaseString.left(1);
        item->setAdjournedPhase(static_cast<ARSExecFltrBlock::Phase>(phaseString.toInt(0, 10)));

        return true;
    }

    switch(item->actionType())
    {
    case ARSExecAction::CallGuide:
        if(arsObjectType == ARSExecWorkflowObject::ActiveLink)
            parseALActCallGuideLine(objectsIndex, static_cast<ARSExecActionCallGuide *>(item), line);
        else
            parseFltrActCallGuideLine(objectsIndex, static_cast<ARSExecActionCallGuide *>(item), line);
        break;
    case ARSExecAction::ChangeFields:
        parseALActChangeFieldsLine(objectsIndex, static_cast<ARSExecActionChangeFields *>(item), line);
        break;
    case ARSExecAction::DDE:
        parseALActDDELine(static_cast<ARSExecActionDDE *>(item), line);
        break;
    case ARSExecAction::DirectSQL:
        parseDirectSQLLine(static_cast<ARSExecActionDirectSQL *>(item), line);
        break;
    case ARSExecAction::GoToGuideLabel:
        if(arsObjectType == ARSExecWorkflowObject::ActiveLink)
            parseALActGoToGuideLabelLine(static_cast<ARSExecActionGoToGuideLabel *>(item), line);
        else
            parseFltrActGoToGuideLabelLine(static_cast<ARSExecActionGoToGuideLabel *>(item), line);
        break;

    case ARSExecAction::Goto:
        parseFltrGoToExecOrderLine(static_cast<ARSExecActionGoto *>(item), line, arsObjectType);
        break;

    case ARSExecAction::Message:
        parseActMessage(static_cast<ARSExecActionMessage *>(item), line);
        break;
    }

    return true;
}

bool LogFileAdapter::parseALActCallGuideLine( ObjectsIndex * objectsIndex, ARSExecActionCallGuide * item, const QString & line )
{
    int index;
    QString property;

    index = line.indexOf(g_LogStrMap[ACTL_CALL_GUIDE_GUIDE]);
    if(index != -1)
    {
        property = line;
        property.remove(0, index + g_LogStrMap[ACTL_CALL_GUIDE_GUIDE].pattern().length());

        item->setGuide(objectsIndex->addGuide(property, ARSExecWorkflowObject::ActiveLink, item));
    }

    return true;
}

bool LogFileAdapter::parseALActGoToGuideLabelLine( ARSExecActionGoToGuideLabel * item, const QString & line )
{
    int index;
    QString property;

    index = line.indexOf(g_LogStrMap[ACTL_GUIDE_LABEL]);
    if(index != -1)
    {
        property = line;
        property.remove(0, index + g_LogStrMap[ACTL_GUIDE_LABEL].pattern().length());

        item->setLabel(property.trimmed());
    }
}

bool LogFileAdapter::parseFltrActGoToGuideLabelLine( ARSExecActionGoToGuideLabel * item, const QString & line )
{
    int index;
    QString property;

    index = line.indexOf(g_LogStrMap[FLTR_GUIDE_LABEL]);
    if(index != -1)
    {
        property = line;
        property.remove(0, index + g_LogStrMap[FLTR_GUIDE_LABEL].pattern().length());

        item->setLabel(property.trimmed());
    }
}

bool LogFileAdapter::parseFltrActCallGuideLine( ObjectsIndex * objectsIndex, ARSExecActionCallGuide * item, const QString & line )
{
    int index;
    QString property = line;

    QRegExp filterRegExp = g_LogStrMap[FLTR_NAME];
    index = filterRegExp.indexIn(property);
    property.remove(0, index + 1);
    property.remove(property.length() - 1, 1);
    item->setGuide(objectsIndex->addGuide(property, ARSExecWorkflowObject::Filter, item));

    return true;
}

/*
bool LogFileAdapter::parseFltrActCallGuideLine( ARSExecActionCallGuide * item, const QString & line )
{
    int index;
    QString property;

    index = line.indexOf(g_LogStrMap[ACTL_CALL_GUIDE_GUIDE]);
    if(index != -1)
    {
        property = line;
        property.remove(0, index + g_LogStrMap[ACTL_CALL_GUIDE_GUIDE].pattern().length());

        item->setGuide(m_index->addGuide(property, item));
    }

    return true;
}*/

bool LogFileAdapter::parseALActChangeFieldsLine( ObjectsIndex * objectsIndex, ARSExecActionChangeFields * item, const QString & line )
{
    int index;
    QString property;

    index = line.indexOf(g_LogStrMap[CHANGE_FIELDS_FIELD]);
    if(index != -1)
    {
        ARSExecItem * blockItem = item->findParent(ARSExecItem::ItemTypeWorkflowBlock);
        ARSExecWorkflowBlock * block = static_cast<ARSExecWorkflowBlock *>(blockItem);

        if(block)
        {
            ARSDummyForm * form = const_cast<ARSDummyForm *>(block->form());
            property = line;
            property.remove(0, index + g_LogStrMap[CHANGE_FIELDS_FIELD].pattern().length());

            QString fieldName = property.trimmed();
            index = fieldName.lastIndexOf(g_LogStrMap[FIELD_ID]);
            int fieldID = 0;
            if(index != -1)
            {
                QString fieldIdStr = fieldName.mid(index + 1, fieldName.length() - (index + 2));
                fieldID = fieldIdStr.toInt();
            }

            item->setField(objectsIndex->addField(form, fieldName, fieldID, item));

            return true;
        }
        else
        {
            qDebug(qPrintable("parseALActChangeFieldsLine: cannot find parent workflow block.\n \"" + line + "\""));
            return false;
        }
    }

    if(line.contains(g_LogStrMap[CHANGE_FIELDS_ATTR]))
    {
        if(line.contains(g_LogStrMap[CHANGE_FILED_READONLY]))
        {
            item->setAccess(ARSExecActionChangeFields::AccessReadOnly);
            return true;
        }
        if(line.contains(g_LogStrMap[CHANGE_FILED_READWRITE]))
        {
            item->setAccess(ARSExecActionChangeFields::AccessReadWrite);
            return true;
        }

        if(line.contains(g_LogStrMap[CHANGE_FILED_DISABLED]))
        {
            item->setAccess(ARSExecActionChangeFields::AccessDisabled);
            return true;
        }
        if(line.contains(g_LogStrMap[CHANGE_FILED_VISIBLE]))
        {
            item->setVisibility(ARSExecActionChangeFields::VisibilityVisible);
            return true;
        }
        if(line.contains(g_LogStrMap[CHANGE_FILED_HIDDEN]))
        {
            item->setVisibility(ARSExecActionChangeFields::VisibilityHidden);
            return true;
        }
    }

    if(line.contains(g_LogStrMap[CHANGE_FILED_FONT]))
    {
        if(line.contains(g_LogStrMap[CHANGE_FILED_FONT_EDIT_FIELD]))
        {
            item->setFont(ARSExecActionChangeFields::FontEditor);
            return true;
        }
        if(line.contains(g_LogStrMap[CHANGE_FILED_FONT_OPTIONAL_FIELD]))
        {
            item->setFont(ARSExecActionChangeFields::FontOptional);
            return true;
        }
        if(line.contains(g_LogStrMap[CHANGE_FILED_FONT_PUSH_BUTTON]))
        {
            item->setFont(ARSExecActionChangeFields::FontPushButton);
            return true;
        }
        if(line.contains(g_LogStrMap[CHANGE_FILED_FONT_SYSTEM_FIELD]))
        {
            item->setFont(ARSExecActionChangeFields::FontSystem);
            return true;
        }
        if(line.contains(g_LogStrMap[CHANGE_FILED_FONT_RADIO_BUTTON]))
        {
            item->setFont(ARSExecActionChangeFields::FontRadioButton);
            return true;
        }
        if(line.contains(g_LogStrMap[CHANGE_FILED_FONT_REAUIRED_FIELD]))
        {
            item->setFont(ARSExecActionChangeFields::FontRequired);
            return true;
        }
        if(line.contains(g_LogStrMap[CHANGE_FILED_FONT_HEADER1]))
        {
            item->setFont(ARSExecActionChangeFields::FontHeader1);
            return true;
        }
        if(line.contains(g_LogStrMap[CHANGE_FILED_FONT_HEADER2]))
        {
            item->setFont(ARSExecActionChangeFields::FontHeader2);
            return true;
        }
        if(line.contains(g_LogStrMap[CHANGE_FILED_FONT_HEADER3]))
        {
            item->setFont(ARSExecActionChangeFields::FontHeader3);
            return true;
        }
        if(line.contains(g_LogStrMap[CHANGE_FILED_FONT_NOTE_TEXT]))
        {
            item->setFont(ARSExecActionChangeFields::FontNote);
            return true;
        }
        if(line.contains(g_LogStrMap[CHANGE_FILED_FONT_DETAIL_TEXT]))
        {
            item->setFont(ARSExecActionChangeFields::FontDetail);
            return true;
        }
    }

    if(line.contains(g_LogStrMap[CHANGE_FILED_LABEL_COLOR]))
    {
        if(line.contains(g_LogStrMap[CHANGE_FILED_LABEL_COLOR_DEFAULT]))
        {
            item->setLabelColor(0);
            return true;
        }
        if(line.contains(g_LogStrMap[CHANGE_FILED_LABEL_COLOR_CUSTOM]))
        {
            property = line.right(QString("000000").length());
            item->setLabelColor(property.toInt(0, 16));
            return true;
        }
    }

    index = line.indexOf(g_LogStrMap[CHANGE_FILED_LABEL]);
    if(index != -1)
    {
        property = line;
        property.remove(0, index + g_LogStrMap[CHANGE_FILED_LABEL].pattern().length());
        item->setLabel(property);
        return true;
    }

    return true;
}

bool LogFileAdapter::parseALActDDELine( ARSExecActionDDE * item, const QString & line )
{
    QString property = line;
    int index;

    index = property.indexOf(g_LogStrMap[DDE_SERVICE]);
    if(index != -1)
    {
        property.remove(0, index + g_LogStrMap[DDE_SERVICE].pattern().length());
        item->setService(property);
        return true;
    }

    index = property.indexOf(g_LogStrMap[DDE_TOPIC]);
    if(index != -1)
    {
        property.remove(0, index + g_LogStrMap[DDE_TOPIC].pattern().length());
        item->setTopic(property);
        return true;
    }

    if(property.contains(g_LogStrMap[DDE_ACTION]))
    {
        if(property.contains(g_LogStrMap[DDE_ACTION_EXECUTE]))
        {
            item->setAction(ARSExecActionDDE::Execute);
            return true;
        }

        if(property.contains(g_LogStrMap[DDE_ACTION_POKE]))
        {
            item->setAction(ARSExecActionDDE::Poke);
            return true;
        }
    }

    index = property.indexOf(g_LogStrMap[DDE_PATH]);
    if(index != -1)
    {
        property.remove(0, index + g_LogStrMap[DDE_PATH].pattern().length());
        item->setPath(property);
        return true;
    }

    index = property.indexOf(g_LogStrMap[DDE_COMMAND]);
    if(index != -1)
    {
        property.remove(0, index + g_LogStrMap[DDE_COMMAND].pattern().length());
        item->setComand(property);
        return true;
    }

    index = property.indexOf(g_LogStrMap[DDE_ITEM]);
    if(index != -1)
    {
        property.remove(0, index + g_LogStrMap[DDE_ITEM].pattern().length());
        item->setItem(property);
        return true;
    }

    return true;
}

bool LogFileAdapter::parseFltrGoToExecOrderLine( ARSExecActionGoto * item, const QString & line,
                                               ARSExecWorkflowObject::ObjectType arsObjectType )
{
    QString property = line;
    int index;

    if(arsObjectType == ARSExecWorkflowObject::Filter)
    {
        index = property.indexOf(g_LogStrMap[FLTR_GOTO_EXECUTION_ORDER_ORDER]);
        if(index != -1)
        {
            property.remove(0, index + g_LogStrMap[FLTR_GOTO_EXECUTION_ORDER_ORDER].pattern().length());
            item->setExecutionOrder(property.trimmed().toInt());
            return true;
        }
    }
    else
    {
        index = property.indexOf(g_LogStrMap[ACTL_GOTO_EXECUTION_ORDER_ORDER]);
        if(index != -1)
        {
            property.remove(0, index + g_LogStrMap[ACTL_GOTO_EXECUTION_ORDER_ORDER].pattern().length());
            item->setExecutionOrder(property.trimmed().toInt());
            return true;
        }
    }

    return false;
}

bool LogFileAdapter::parseActMessage( ARSExecActionMessage * item, const QString & line )
{
    if(line.endsWith(": " + g_LogStrMap[MESSAGE].pattern()))
        return true;

    if(item->text().isEmpty())
        item->setText(line);
    else
        item->setText(item->text() + "\n" + line);

    return true;
}

bool LogFileAdapter::parseDirectSQLLine( ARSExecActionDirectSQL * item, const QString & line )
{
    QString property = line;

    if(property.contains(g_LogStrMap[DIRECT_SQL]) || property.startsWith(g_LogStrMap[DIRECT_SQL_SERVER].pattern()))
        return true;

    if(property.startsWith(g_LogStrMap[DIRECT_SQL_SQL].pattern()))
        property.remove(0, g_LogStrMap[DIRECT_SQL_SQL].pattern().length() + 1);

    if(item->command().isEmpty())
        item->setCommand(property);
    else
        item->setCommand(item->command() + "\n" + property);

    return true;
}

bool LogFileAdapter::parseFieldAssign( ObjectsIndex * objectsIndex, ARSExecFieldAssign * item, const QString & line )
{
    int index;
    QString property = line;

    if(!item->field())
    {
        QRegExp regExp = g_LogStrMap[FIELD_ASSIGN];
        ARSExecWorkflowBlock * block =
                static_cast<ARSExecWorkflowBlock *>(item->findParent(ARSExecItem::ItemTypeWorkflowBlock));

        if(!block)
            return false;

        ARSDummyForm * form = const_cast<ARSDummyForm *>(block->form());

        if(!form)
            return false;

        index = regExp.indexIn(property);
        index += regExp.matchedLength();

        QString fieldName = property.left(index - 1).trimmed();
        index = fieldName.lastIndexOf(g_LogStrMap[FIELD_ID]);
        int fieldID = 0;
        if(index != -1)
        {
            QString fieldIdStr = fieldName.mid(index + 1, fieldName.length() - (index + 2));
            fieldID = fieldIdStr.toInt();
        }

        item->setField(objectsIndex->addField(form, fieldName, fieldID, item));
        property.remove(0, index);
        item->setValue(property.trimmed());
    }
    else
        item->setValue(item->value() + "\n" + property.trimmed());

    return true;
}

bool LogFileAdapter::parseSQLLine( ARSExecSQLLine * item, const QString & line )
{
    item->setText(line);
    return true;
}

bool LogFileAdapter::parseAPILine( ARSExecAPILine * item, const QString & line )
{
    item->setText(line);
    return true;
}

#if 0

bool LogFileAdapter::parseALActSetFieldsLine( ARSExecAction * item, const QString & line )
{
    QString property;
    QStringList setList;

    if(line.contains(g_LogStrMap[ACTL_SET_FIELDS]))
        return true;

    if(line.contains(g_LogStrMap[ACTL]))
    {
        property = line;
        property.remove(0, g_LogStrMap[ACTL].pattern().length());
        property = property.trimmed();
        setList = item->properties.value(0).toStringList();
        setList.append(property);
        item->properties.insert(0, setList);
    }

    return true;
}

bool LogFileAdapter::parseFltrActSetFieldsLine( ARSExecAction * item, const QString & line )
{
    QString property;
    QStringList setList;

    if(line.contains(g_LogStrMap[FLTR_SET_FIELDS]))
        return true;

    if(line.contains(g_LogStrMap[FLTR]))
    {
        property = line;
        property.remove(0, g_LogStrMap[FLTR].pattern().length());
        property = property.trimmed();
        setList = item->properties.value(0).toStringList();
        setList.append(property);
        item->properties.insert(0, setList);
    }

    return true;
}

#endif

ARSExecItem * LogFileAdapter::element2item( ObjectsIndex * objectsIndex, const QDomElement & element, ARSExecItem * parent )
{
    ARSExecItem * item;

    if(element.tagName() == "ARSExecModelRootItem")
        item = parent;
    else
        item = itemFromName(element.tagName(), parent);

    const QMetaObject * itemMetaObject = item->metaObject();

    for(int i = 1; i < itemMetaObject->propertyCount(); i++)
    {
        QMetaProperty itemMetaProperty = itemMetaObject->property(i);
        if(itemMetaProperty.isWritable())
        {
            QString propertyString = element.attribute(itemMetaProperty.name());
            QVariant propertyValue = string2Property(objectsIndex, propertyString, itemMetaProperty, item);
            item->setProperty(itemMetaProperty.name(), propertyValue);
        }
    }

    if(element.hasAttribute("comment"))
        item->setComment(element.attribute("comment"));

    QDomNodeList childList = element.childNodes();
    for(int i = 0; i < childList.size(); i++)
        element2item(objectsIndex, childList.at(i).toElement(), item);

    return item;
}

QVariant LogFileAdapter::string2Property( ObjectsIndex * objectsIndex, const QString & propertyString,
                                        const QMetaProperty & itemMetaProperty, ARSExecItem * item )
{
    if(propertyString.isEmpty())
        return QVariant();

    if(itemMetaProperty.isEnumType())
        return propertyString.toInt();

    if(itemMetaProperty.type() == QVariant::String)
        return propertyString;

    if(itemMetaProperty.type() == QVariant::Int)
        return propertyString;

    if(QString(itemMetaProperty.typeName()) == "ARSDummyActiveLink*")
    {
        ARSDummyActiveLink * activeLink = objectsIndex->addActiveLink(propertyString, item);
        return QVariant::fromValue(activeLink);
    }

    if(QString(itemMetaProperty.typeName()) == "ARSDummyFilter*")
    {
        ARSDummyFilter * filter = objectsIndex->addFilter(propertyString, item);
        return QVariant::fromValue(filter);
    }

    if(QString(itemMetaProperty.typeName()) == "ARSDummyForm*")
    {
        ARSDummyForm * form = objectsIndex->addForm(propertyString, item);
        return QVariant::fromValue(form);
    }

    if(QString(itemMetaProperty.typeName()) == "ARSDummyField*")
    {
        QString formName = propertyString.split(QChar::Nbsp).first();
        ARSDummyForm * form = static_cast<ARSDummyForm *>(objectsIndex->findObject(formName, ARSObject::Form));

        if(!form)
            form = objectsIndex->addForm(formName, item);
        ARSDummyField * field = objectsIndex->addField(form, propertyString.split(QChar::Nbsp).at(1), 0, item);
        return QVariant::fromValue(field);
    }

    if(QString(itemMetaProperty.typeName()) == "ARSDummyGuide*")
    {
        QString guideTypeStr = propertyString.split(QChar::Nbsp).first();
        QString guideName = propertyString.split(QChar::Nbsp).at(1);
        ARSExecWorkflowObject::ObjectType objectsType = static_cast<ARSExecWorkflowObject::ObjectType>(guideTypeStr.toInt());
        ARSDummyGuide * guide = objectsIndex->addGuide(guideName, objectsType, item);
        return QVariant::fromValue(guide);
    }

    return QVariant();
}

LogFileAdapter::ObjectsManagment LogFileAdapter::itemMark( const QString & line )
{
    if(line.contains(g_LogStrMap[WFLG]))
        return WorkflowRoot;


    if(line.contains(g_LogStrMap[ACTL_PACKAGE_START]) ||
       line.contains(g_LogStrMap[FLTR_PACKAGE_START]) ||
       line.contains(g_LogStrMap[FLTR_PACKAGE_RESTART])
      )
        return WorkflowBlockBegin;

    if(line.contains(g_LogStrMap[ACTL_PACKAGE_END]) ||
       line.contains(g_LogStrMap[FLTR_PACKAGE_END])
      )
        return WorkflowBlockEnd;

    if(line.contains(g_LogStrMap[ACTL_GUIDE_END]) ||
       line.contains(g_LogStrMap[FLTR_GUIDE_END])
      )
        return WorkflowGuideEnd;

    if(line.contains(g_LogStrMap[ACTL_GUIDE_START]))
        return WorkflowGuideBegin;

    if(line.contains(g_LogStrMap[ACTL_EXECUTION]) ||
       line.contains(g_LogStrMap[FLTR_EXECUTION]) ||
       line.contains(g_LogStrMap[FLTR_SKIPPED])
      )
        return WorkflowObjectBegin;

    if(line.contains(g_LogStrMap[FIELD_ASSIGN]))
        return WorkflowFieldAssign;

    /*! \todo */
    for(int i = 27; i <= 49; i++)
    {
        if(line.contains(": " + g_LogStrMap[i].pattern()))
            return WorkflowActionBegin;
    }

    if(line.contains(g_LogStrMap[FLTR_GOTO_EXECUTION_ORDER]) ||
       line.contains(g_LogStrMap[ACTL_GOTO_EXECUTION_ORDER]))
        return WorkflowActionBegin;

    return Unknown;
}


/*
int LogFileAdapter::logPackageStart( const QString & line ) const
{

    return LogObject::Unknown;
}

int LogFileAdapter::logObjectStart( const QString & line ) const
{
    if(line.contains(g_LogStrMap[ACTL_EXECUTION]))
        return LogObject::Actl;

    if(line.contains(g_LogStrMap[FLTR_EXECUTION]))
        return LogObject::Fltr;

    return LogObject::Unknown;
}*/

ARSExecWorkflowObject::ObjectType LogFileAdapter::objectType( const QString & line )
{
    if(line.startsWith(g_LogStrMap[ACTL].pattern()))
        return ARSExecWorkflowObject::ActiveLink;

    if(line.startsWith(g_LogStrMap[FLTR].pattern()))
        return ARSExecWorkflowObject::Filter;

    return ARSExecWorkflowObject::Unknown;
}

ARSExecAction::ActionType LogFileAdapter::actionType( const QString & line )
{
    if(line.contains(g_LogStrMap[CALL_GUIDE]))
        return ARSExecAction::CallGuide;

    if(line.contains(g_LogStrMap[CLOSE_WINDOW]))
        return ARSExecAction::CloseWindow;

    if(line.contains(g_LogStrMap[COMMIT_CHANGES]))
        return ARSExecAction::CommitChanges;

    if(line.contains(g_LogStrMap[DDE]))
        return ARSExecAction::DDE;

    if(line.contains(g_LogStrMap[DIRECT_SQL]))
        return ARSExecAction::DirectSQL;

    if(line.contains(g_LogStrMap[GOTO_GUIDE_LABEL]))
        return ARSExecAction::GoToGuideLabel;

    if(line.contains(g_LogStrMap[MESSAGE]) ||
       line.contains(g_LogStrMap[FLTR_MESSAGE]))
        return ARSExecAction::Message;

    if(line.contains(g_LogStrMap[NOTIFY]))
        return ARSExecAction::Notify;

    if(line.contains(g_LogStrMap[RUN_MACRO]))
        return ARSExecAction::RunMacro;

    if(line.contains(g_LogStrMap[ACTL_RUN_PROCESS]) ||
       line.contains(g_LogStrMap[FLTR_RUN_PROCESS]))
        return ARSExecAction::RunProcess;

    if(line.contains(g_LogStrMap[OPEN_DIALOG]))
        return ARSExecAction::OpenWindow;

    if(line.contains(g_LogStrMap[ACTL_SET_FIELDS]) ||
       line.contains(g_LogStrMap[FLTR_SET_FIELDS]))
        return ARSExecAction::SetFields;

    if(line.contains(g_LogStrMap[CHANGE_FIELDS]))
        return ARSExecAction::ChangeFields;

    if(line.contains(g_LogStrMap[PUSH_FIELDS]))
        return ARSExecAction::PushFields;

    if(line.contains(g_LogStrMap[EXIT_GUIDE]))
        return ARSExecAction::ExitGuide;

    if(line.contains(g_LogStrMap[FLTR_GOTO_EXECUTION_ORDER]) ||
       line.contains(g_LogStrMap[ACTL_GOTO_EXECUTION_ORDER]))
        return ARSExecAction::Goto;

    if(line.contains(g_LogStrMap[LOG_TO_FILE]))
        return ARSExecAction::LogToFile;

    if(line.contains(g_LogStrMap[SERVICE]))
        return ARSExecAction::Service;

    return ARSExecAction::ActionTypeNone;
}

inline ARSExecWorkflowBlock::Event LogFileAdapter::eventType( const QString & line )
{
    if(line.contains(g_LogStrMap[EVENT_ON_CONTROL]))
        return ARSExecWorkflowBlock::EventControl;

    if(line.contains(g_LogStrMap[EVENT_ON_WINDOW_OPEN]))
        return ARSExecWorkflowBlock::EventWindowOpen;

    if(line.contains(g_LogStrMap[EVENT_ON_SET_DEFAULT]))
        return ARSExecWorkflowBlock::EventSetDefault;

    if(line.contains(g_LogStrMap[EVENT_ON_GAIN_FOCUS]))
        return ARSExecWorkflowBlock::EventGainFocus;

    if(line.contains(g_LogStrMap[EVENT_ON_LOADED]))
        return ARSExecWorkflowBlock::EventLoaded;

    if(line.contains(g_LogStrMap[EVENT_GET]))
        return ARSExecWorkflowBlock::EventGet;

    if(line.contains(g_LogStrMap[EVENT_ON_MENU_CHOICE]))
        return ARSExecWorkflowBlock::EventMenuChoice;

    if(line.contains(g_LogStrMap[EVENT_ON_RETURN]))
        return ARSExecWorkflowBlock::EventReturn;

    if(line.contains(g_LogStrMap[EVENT_ON_SUBMIT]))
        return ARSExecWorkflowBlock::EventSubmit;

    if(line.contains(g_LogStrMap[EVENT_CREATE]))
        return ARSExecWorkflowBlock::EventCreate;

    if(line.contains(g_LogStrMap[EVENT_SET]))
        return ARSExecWorkflowBlock::EventSet;

    if(line.contains(g_LogStrMap[EVENT_DELETE]))
        return ARSExecWorkflowBlock::EventDelete;

    if(line.contains(g_LogStrMap[EVENT_ON_AFTER_SUBMIT]))
        return ARSExecWorkflowBlock::EventAfterSubmit;

    if(line.contains(g_LogStrMap[EVENT_ON_QUERY]))
        return ARSExecWorkflowBlock::EventQuery;

    if(line.contains(g_LogStrMap[EVENT_ON_DISPLAY]))
        return ARSExecWorkflowBlock::EventDisplay;

    if(line.contains(g_LogStrMap[EVENT_ON_WINDOW_CLOSE]))
        return ARSExecWorkflowBlock::EventWindowClose;

    if(line.contains(g_LogStrMap[EVENT_ON_MODIFY]))
        return ARSExecWorkflowBlock::EventModify;

    if(line.contains(g_LogStrMap[EVENT_ON_UN_DISPLAY]))
        return ARSExecWorkflowBlock::EventUnDisplay;

    return ARSExecWorkflowBlock::None;
}

inline ARSExecActlBlock::ScreenType LogFileAdapter::screenType( const QString & line )
{
    if(line.contains(g_LogStrMap[SCREEN_TYPE_QUERY]))
        return ARSExecActlBlock::ScreenQuery;

    if(line.contains(g_LogStrMap[SCREEN_TYPE_CREATE]))
        return ARSExecActlBlock::ScreenCreate;

    if(line.contains(g_LogStrMap[SCREEN_TYPE_DIALOG]))
        return ARSExecActlBlock::ScreenDialog;

    if(line.contains(g_LogStrMap[SCREEN_TYPE_SET]))
        return ARSExecActlBlock::ScreenSet;

    return ARSExecActlBlock::ScreenNone;
}

inline int LogFileAdapter::serverPropertiesLen( const QString & line )
{
    int index;

    index = line.indexOf(g_LogStrMap[USER]);

    if(!index)
        return 0;

    return line.indexOf(">", index) + 1;
}

ARSExecItem * LogFileAdapter::itemFromName( const QString & name, ARSExecItem * parent )
{
    if(name == "ARSExecActl")
            return new ARSExecActl(parent);

    if(name == "ARSExecFltr")
            return new ARSExecFltr(parent);

    if(name == "ARSExecRootItem")
            return new ARSExecRootItem(parent);

    if(name == "ARSExecActlBlock")
            return new ARSExecActlBlock(parent);

    if(name == "ARSExecFltrBlock")
            return new ARSExecFltrBlock(parent);

    if(name == "ARSExecGuide")
            return new ARSExecGuide(parent);

    if(name == "ARSExecActionCallGuide")
            return new ARSExecActionCallGuide(parent);

    if(name == "ARSExecActionChangeFields")
            return new ARSExecActionChangeFields(parent);

    if(name == "ARSExecActionCloseWindow")
            return new ARSExecActionCloseWindow(parent);

    if(name == "ARSExecActionCommitChanges")
            return new ARSExecActionCommitChanges(parent);

    if(name == "ARSExecActionDDE")
            return new ARSExecActionDDE(parent);

    if(name == "ARSExecActionDirectSQL")
            return new ARSExecActionDirectSQL(parent);

    if(name == "ARSExecActionDSOAction")
            return new ARSExecActionDSOAction(parent);

    if(name == "ARSExecActionExitGuide")
            return new ARSExecActionExitGuide(parent);

    if(name == "ARSExecActionGoToGuideLabel")
            return new ARSExecActionGoToGuideLabel(parent);

    if(name == "ARSExecActionGoto")
            return new ARSExecActionGoto(parent);

    if(name == "ARSExecActionLogToFile")
            return new ARSExecActionLogToFile(parent);

    if(name == "ARSExecActionMessage")
            return new ARSExecActionMessage(parent);

    if(name == "ARSExecActionNotify")
            return new ARSExecActionNotify(parent);

    if(name == "ARSExecActionOLEAutomation")
            return new ARSExecActionOLEAutomation(parent);

    if(name == "ARSExecActionOpenWindow")
            return new ARSExecActionOpenWindow(parent);

    if(name == "ARSExecActionRunMacro")
            return new ARSExecActionRunMacro(parent);

    if(name == "ARSExecActionRunProcess")
            return new ARSExecActionRunProcess(parent);

    if(name == "ARSExecActionWait")
            return new ARSExecActionWait(parent);

    if(name == "ARSExecActionPushFields")
            return new ARSExecActionPushFields(parent);

    if(name == "ARSExecActionSetFields")
            return new ARSExecActionSetFields(parent);

    if(name == "ARSExecFieldAssign")
            return new ARSExecFieldAssign(parent);

    if(name == "ARSExecSQLLine")
            return new ARSExecSQLLine(parent);

    if(name == "ARSExecAPILine")
            return new ARSExecAPILine(parent);

    if(name == "ARSExecModelRootItem")
            return new ARSExecModelRootItem();

    qDebug(qPrintable("LogFileAdapter::itemFromName: \"" + name + "\" is not correct"));
    return 0;
}

ARSExecAction * LogFileAdapter::createAction( ARSExecAction::ActionType type, ARSExecItem * parent )
{
    ARSExecAction * action = 0;

    switch(type)
    {
    case ARSExecAction::CallGuide:
        action = new ARSExecActionCallGuide(parent);
    break;
    case ARSExecAction::ChangeFields:
        action = new ARSExecActionChangeFields(parent);
    break;
    case ARSExecAction::CloseWindow:
        action = new ARSExecActionCloseWindow(parent);
    break;
    case ARSExecAction::CommitChanges:
        action = new ARSExecActionCommitChanges(parent);
    break;
    case ARSExecAction::DDE:
        action = new ARSExecActionDDE(parent);
    break;
    case ARSExecAction::DirectSQL:
        action = new ARSExecActionDirectSQL(parent);
    break;
    case ARSExecAction::DSOAction:
        action = new ARSExecActionDSOAction(parent);
    break;
    case ARSExecAction::ExitGuide:
        action = new ARSExecActionExitGuide(parent);
    break;
    case ARSExecAction::GoToGuideLabel:
        action = new ARSExecActionGoToGuideLabel(parent);
    break;
    case ARSExecAction::Goto:
        action = new ARSExecActionGoto(parent);
    break;
    case ARSExecAction::LogToFile:
        action = new ARSExecActionLogToFile(parent);
    break;
    case ARSExecAction::Message:
        action = new ARSExecActionMessage(parent);
    break;
    case ARSExecAction::Notify:
        action = new ARSExecActionNotify(parent);
    break;
    case ARSExecAction::OLEAutomation:
        action = new ARSExecActionOLEAutomation(parent);
    break;
    case ARSExecAction::OpenWindow:
        action = new ARSExecActionOpenWindow(parent);
    break;
    case ARSExecAction::RunMacro:
        action = new ARSExecActionRunMacro(parent);
    break;
    case ARSExecAction::RunProcess:
        action = new ARSExecActionRunProcess(parent);
    break;
    case ARSExecAction::Wait:
        action = new ARSExecActionWait(parent);
    break;
    case ARSExecAction::PushFields:
        action = new ARSExecActionPushFields(parent);
    break;
    case ARSExecAction::SetFields:
        action = new ARSExecActionSetFields(parent);
    break;
    case ARSExecAction::Service:
        action = new ARSExecActionService(parent);
    break;
    }

    return action;
}

LogFileAdapter::LineType LogFileAdapter::lineType( const QString & line )
{
    if(line.startsWith(g_LogStrMap[ACTL].pattern()))
        return LineActiveLink;

    if(line.startsWith(g_LogStrMap[FLTR].pattern()))
        return LineFilter;

    if(line.startsWith(g_LogStrMap[LINE_SQL].pattern()))
        return LineSql;

    if(line.startsWith(g_LogStrMap[LINE_API].pattern()))
        return LineApi;

    if(line.startsWith(g_LogStrMap[LINE_CLAT].pattern()))
        return LineClat;

    return LineUnknown;
}

int LogFileAdapter::createDateMonth( const QString & line )
{
    if(line.contains(g_LogStrMap[MONTH_JAN]))
        return 1;

    if(line.contains(g_LogStrMap[MONTH_FEB]))
        return 2;

    if(line.contains(g_LogStrMap[MONTH_MAR]))
        return 3;

    if(line.contains(g_LogStrMap[MONTH_APR]))
        return 4;

    if(line.contains(g_LogStrMap[MONTH_MAY]))
        return 5;

    if(line.contains(g_LogStrMap[MONTH_JUN]))
        return 6;

    if(line.contains(g_LogStrMap[MONTH_JUL]))
        return 7;

    if(line.contains(g_LogStrMap[MONTH_AUG]))
        return 8;

    if(line.contains(g_LogStrMap[MONTH_SEP]))
        return 9;

    if(line.contains(g_LogStrMap[MONTH_OCT]))
        return 10;

    if(line.contains(g_LogStrMap[MONTH_NOV]))
        return 11;

    if(line.contains(g_LogStrMap[MONTH_DEC]))
        return 12;

    return -1;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
